


#ifndef SAR_SYSTEM_VM_AGENT_H
#define SAR_SYSTEM_VM_AGENT_H

#include <kernel/kernel.h>
#include <kernel/handle/handle.h>
#include <kernel/userid/userid.h>

#include "header.h"
#include "datum.h"

#define VM_AGENT_SLEEPING 0
#define VM_AGENT_AWAKE 1
#define VM_AGENT_DEAD 2

/* An Agent represents a node of execution.  They are implemented
 * as coroutines, but from the programmer's perspective they are just
 * regular functions.  Agents are placed in a wait queue whenever
 * someone (user or other agent) writes to their input stream.
 * Execution continues in the current agent until another agent's
 * response is needed, at which point the agent "yields" and 
 * execution resumes with the next agent in the queue.  This creates
 * an inherently distributed, event-driven environment which is easy
 * to parallelize.  In a cluster, the agents are distributed such
 * that agents which frequently communicate reside on the same
 * computer, and each processor has its own wait queue. 
 */

typedef struct Agent {

	vm_Header Header;
	userid ID;

	/* We execute code from a handle to allow agents to "sleep"
	 * by freeing local caches.  Since the handle might be 
	 * sourced from disk, a sleeping agent will take up very
	 * little memory. 
	 */
	handle ByteStream;
	handle InputStream;

	/* The agent places itself in a wait queue when it yields.
	 * A multi-processor system requires one queue for each
	 * processor, so the agent must know to which queue it
	 * belongs. 
	 */
	handle WaitQueue;

	/* Agents which have no references are eventually terminated
	 * by a garbage collection agent.  Agents never explicitly
	 * "exit", so this collection is necessary. 
	 */

	int ReferenceCount;

	char *ByteCache;	/* local cache */
	size ByteCacheSize;

	/* pointers to segments within ByteChache */
	char *TextSegment;
	vm_Datum *DataSegment;
	int *CodeSegment;

	/* The agent's state is loaded from and saved to the wait
	 * queue to allow each agent to be re-entrant.
	 */

	/* The agent must know if it is asleep or not... */
	char Status;

} vm_Agent;

vm_Agent *vm_agent_request (handle, userid);
void vm_agent_release (vm_Agent *);
int vm_agent_wake (vm_Agent *_agent);
int vm_agent_sleep (vm_Agent *_agent);

#endif
